package com.atguigu.mall.mallproduct.controller;

import java.util.Arrays;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.mall.mallproduct.entity.PmsSpuInfoEntity;
import com.atguigu.mall.mallproduct.service.PmsSpuInfoService;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.R;

/**
 * spu信息
 *
 * @author Fuc
 * @email leftbear@gmail.com
 * @date 2020-10-21 14:01:49
 */
@RestController
@RequestMapping("mallproduct/pmsspuinfo")
public class PmsSpuInfoController {
  @Autowired private PmsSpuInfoService pmsSpuInfoService;

  @PostMapping("/{spuId}/up")
  public R list(@PathVariable("spuId") Long spuId) {
    pmsSpuInfoService.up(spuId);
    return R.ok();
  }

  /** 列表 */
  /**
   * 1、每一个需要缓存的数据我们都来指定要放到那个名字的缓存。【缓存的分区（按照业务类型分）】
   * 2、Cacheable(("category")
   *     代表当前方法的结果需要缓存，如果缓存中存，方法不用调用
   *     如果缓存中没有，会调用方法，最后将方法的结果取入缓存
   * 3、默认行为
   *    1)、如果缓存中，方法不调用。
   *    2)、key默认自动生成；缓存名字::SimpleKey []（自动生成的key值）
   *    3)、缓存的value值。默认使用jdk序列化机制，将序列化后的数据存到redis
   *    4)、默认ttl时间 -1
   *
   *    自定义：
   *    1)、指定生成的缓存使用的key：key属性指定，接受一个SpEL
   *        SpEL的详细语法参见官网
   *    2)、指定生成的数据的存活时间：配置文件修改ttl
   *    3)、将数据保存为json格式
   *           CacheAutoConfiguration
   *
   * 4、Spring-Cache的不足
   *    1)、读模式：
   *        缓存穿透：查询一个null数据。解决：缓存空数据；ache-null-values=true
   *        缓存击穿：大量并发进来同时查询一个正好过期的数据。解决：加锁；?
   *        缓存雪崩：大量的key同时过期。解决：加随机时间。加上过期时间。：spring.cache.redis.time-to-live=360000
   *    2)、写模式：(缓存与数据库一致）
   *         1)、读写加锁。
   *         2)、引入Canal,感知到MySQL的更新去更新数据库
   *         3)、读多写多，直接去数据库查询就行
   *
   *   总结：
   *      常规数据（读多写少，即时性，一致性要求不高的数据）;完全可以使用Spring-Cache
   *      特殊数据：特殊设计
   *
   *   原理：
   *       CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写
   */
  @Cacheable(value={"spu"},key="#root.method.name",sync = true) // 代表当前方法的结果需要缓存，如果缓存中有，方法不用调用，如果缓存中没有，会调用方法将结果放入缓存
  @RequestMapping("/list")
  public R list(@RequestParam Map<String, Object> params) {
    PageUtils page = pmsSpuInfoService.queryPage(params);

    return R.ok().put("page", page);
  }






  /** 信息 */
  @RequestMapping("/info/{id}")
  public R info(@PathVariable("id") Long id) {
    PmsSpuInfoEntity pmsSpuInfo = pmsSpuInfoService.getById(id);

    return R.ok().put("pmsSpuInfo", pmsSpuInfo);
  }

  /** 保存 */
  @RequestMapping("/save")
  public R save(@RequestBody PmsSpuInfoEntity pmsSpuInfo) {
    pmsSpuInfoService.save(pmsSpuInfo);

    return R.ok();
  }

  /**
   * 修改 CacheEvict：失效模式
   * 1、同时进行多种缓存操作Caching
   * 2、指定删除某个分区下的所有数据 @CacheEvict(value="category",allEntries=true)
   * 3、存储同一类型的数据，都可以指定成同一个分区。分区名默认就是缓存的前缀
   */
  @CacheEvict(
      value = {"spu"},
      key = "'stringInformation'")
  @RequestMapping("/update")
  public R update(@RequestBody PmsSpuInfoEntity pmsSpuInfo) {
    pmsSpuInfoService.updateById(pmsSpuInfo);

    return R.ok();
  }

  /** 删除 */
  @RequestMapping("/delete")
  public R delete(@RequestBody Long[] ids) {
    pmsSpuInfoService.removeByIds(Arrays.asList(ids));

    return R.ok();
  }
}
